package cn.felord.security.autoconfigure;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * The type Abstract login channel processor.
 *
 * @param <T> the type parameter
 * @author n1
 * @since 2021 /6/29 9:32
 */
public abstract class AbstractLoginChannelProcessor<T extends AbstractAuthenticationToken> implements LoginChannelProcessor<T> {
    /**
     * The Authentication details source.
     */
    protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
    private final String channel;
    private final AuthenticationProvider AppAuthenticationProvider;

    /**
     * Instantiates a new Abstract login channel processor.
     *
     * @param channel                   the channel
     * @param appAuthenticationProvider the app authentication provider
     */
    public AbstractLoginChannelProcessor(String channel, AuthenticationProvider appAuthenticationProvider) {
        this.channel = channel;
        AppAuthenticationProvider = appAuthenticationProvider;
    }

    @Override
    public T authenticationRequest(HttpServletRequest request) throws IOException {
        T authenticationRequest = doAuthenticationRequest(request);
        setDetails(request, authenticationRequest);
        return authenticationRequest;
    }


    /**
     * Do authentication request t.
     *
     * @param request the request
     * @return the t
     * @throws IOException the io exception
     */
    public abstract T doAuthenticationRequest(HttpServletRequest request) throws IOException;

    @Override
    public AuthenticationProvider getProvider() {
        return this.AppAuthenticationProvider;
    }

    @Override
    public boolean supports(String channel) {
        return this.channel.equals(channel);
    }


    /**
     * Sets details.
     *
     * @param request     the request
     * @param authRequest the auth request
     */
    protected void setDetails(HttpServletRequest request,
                              T authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
